This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

ds2 <- readRDS("ds2.rds")

umapplot

ds0 <- readRDS("ds0.rds")

周细胞的存在

library(igraph)

基因表达

ds2 -> ds1 无监督聚类


ds2data <- get_data_table(ds2FbM,type = "data")
ds1data <- get_data_table(ds1FbM,type = "data")

# ds2expr <- data.frame(expr = ds2data["DCN",], sample = "ds2", gene = "DCN")
# rownames(ds2expr) <- NULL
# ds1expr <- data.frame(expr = ds1data["DCN",], sample = "ds1")
# rownames(ds1expr) <- NULL
# merge_expr <- rbind(ds2expr,ds1expr)

genes_to_show <- c("DCN","LUM","MMP2","ACTA2","TNFRSF11B","FBLN1")

func <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func,"ds1",ds1data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func,"ds2",ds2data))
{
  merge_expr <- rbind(merge_expr,i)
}


rownames(merge_expr) <- NULL



Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)
ggsave("unds2tods1.svg", device = svg, plot = ggobj, height = 6, width = 10)

监督聚类结果

这里使用numeric的分群

ds2FbM <- subset(ds2,ident = "1")
ds1FbM <- subset(ds1,ident = "1")

ds2data <- get_data_table(ds2FbM,type = "data")
ds1data <- get_data_table(ds1FbM,type = "data")

# ds2expr <- data.frame(expr = ds2data["DCN",], sample = "ds2", gene = "DCN")
# rownames(ds2expr) <- NULL
# ds1expr <- data.frame(expr = ds1data["DCN",], sample = "ds1")
# rownames(ds1expr) <- NULL
# merge_expr <- rbind(ds2expr,ds1expr)

genes_to_show <- c("DCN","LUM","MMP2","ACTA2","TNFRSF11B","FBLN1")

func1 <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func1,"ds1",ds1data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func1,"ds2",ds2data))
{
  merge_expr <- rbind(merge_expr,i)
}


rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)

ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)

ggsave("supds2tods1.svg", device = svg, plot = ggobj, height = 6, width = 10)

ds2 -> ds0

无监督聚类


ds2data <- get_data_table(ds2FbM,type = "data")
ds0data <- get_data_table(ds0FbM,type = "data")

genes_to_show <- c("DCN","LUM","MMP2","ACTA2","TNFRSF11B","FBLN1")

func <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func,"ds0",ds0data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func,"ds2",ds2data))
{
  merge_expr <- rbind(merge_expr,i)
}

rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)

监督聚类

ds2data <- get_data_table(ds2FbM,type = "data")
ds0data <- get_data_table(ds0FbM,type = "data")

genes_to_show <- c("DCN","LUM","MMP2","ACTA2","TNFRSF11B","FBLN1")

func <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func,"ds0",ds0data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func,"ds2",ds2data))
{
  merge_expr <- rbind(merge_expr,i)
}

rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)

ggsave("supds2tods0.svg", device = svg, plot = ggobj, height = 6, width = 10)

ds0 -> ds2

##无监督聚类


ds2data <- get_data_table(ds2FbM,type = "data")
ds0data <- get_data_table(ds0FbM,type = "data")

# genes_to_show <- c("IGFBP2","MGP","MYH11","DCN","TNFRSF11B")
genes_to_show <- c("DCN","LUM","MMP2","ACTA2","TNFRSF11B","FBLN1")

func <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func,"ds0",ds0data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func,"ds2",ds2data))
{
  merge_expr <- rbind(merge_expr,i)
}

rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)

ggsave("2_unds0tods2.svg", device = svg, plot = ggobj, height = 6, width = 10)

监督聚类

ds0 -> ds2


func <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func,"ds0",ds0data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func,"ds2",ds2data))
{
  merge_expr <- rbind(merge_expr,i)
}

rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)
ggobj
ggsave("2_supds0tods2.svg", device = svg, plot = ggobj, height = 6, width = 10)

ds0 -> ds1

##无监督聚类

genes_to_show <- c("DCN","LUM","MMP2","ACTA2","TNFRSF11B","FBLN1")

func <- function(gene, sample, datable){
  data.frame(expr = datable[gene,], sample = sample, gene = gene)
}

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func,"ds0",ds0data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func,"ds1",ds1data))
{
  merge_expr <- rbind(merge_expr,i)
}

rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)
ggobj
ggsave("2_unds0tods1.svg", device = svg, plot = ggobj, height = 6, width = 10)

监督聚类

ds0 -> ds1

merge_expr <- data.frame()

for (i in lapply(genes_to_show, func1,"ds0",ds0data))
{
  merge_expr <- rbind(merge_expr,i)
}
for (i in lapply(genes_to_show, func1,"ds1",ds1data))
{
  merge_expr <- rbind(merge_expr,i)
}

rownames(merge_expr) <- NULL

Data_summary <- Rmisc::summarySE(merge_expr, measurevar="expr", groupvars=c("sample","gene"))
head(Data_summary)


ggobj <- ggplot(merge_expr,aes(x = gene, y = expr,fill = sample)) +
  geom_split_violin(trim= F, color="white", scale = "area") + 
  geom_point(data = Data_summary,aes(x = gene, y= expr), pch=19,
             position=position_dodge(0.2),size= 1) + #绘制均值位置
  geom_errorbar(data = Data_summary, aes(ymin = expr-ci, ymax= expr+ci), 
                width= 0.05, 
                position= position_dodge(0.2), #误差线位置,和均值位置相匹配
                color="black",
                alpha = 0.7,
                size= 0.5) +
  scale_fill_manual(values = c("#b1d6fb", "#fd9999"))+ 
  labs(y=("Log2 expression"),x=NULL,title = "Split violin") + 
  theme_classic()+ mytheme + stat_compare_means(aes(group = sample),
                     label = "p.format",
                     method = "wilcox.test",
                     label.y = max(merge_expr$expr),
                      hide.ns = F)
ggobj

mytheme <- theme(plot.title = element_text(size = 12,color="black",hjust = 0.5),
                     axis.title = element_text(size = 12,color ="black"), 
                     axis.text = element_text(size= 12,color = "black"),
                     panel.grid.minor.y = element_blank(),
                     panel.grid.minor.x = element_blank(),
                     axis.text.x = element_text(angle = 45, hjust = 1 ),
                     panel.grid=element_blank(),
                     legend.position = "top",
                     legend.text = element_text(size= 12),
                     legend.title= element_text(size= 12)) 

# https://stackoverflow.com/a/45614547
GeomSplitViolin <- ggproto("GeomSplitViolin", GeomViolin, draw_group = function(self, data, ..., draw_quantiles = NULL){
  data <- transform(data, xminv = x - violinwidth * (x - xmin), xmaxv = x + violinwidth * (xmax - x))
  grp <- data[1,'group']
  newdata <- plyr::arrange(transform(data, x = if(grp%%2==1) xminv else xmaxv), if(grp%%2==1) y else -y)
  newdata <- rbind(newdata[1, ], newdata, newdata[nrow(newdata), ], newdata[1, ])
  newdata[c(1,nrow(newdata)-1,nrow(newdata)), 'x'] <- round(newdata[1, 'x']) 
  if (length(draw_quantiles) > 0 & !scales::zero_range(range(data$y))) {
    stopifnot(all(draw_quantiles >= 0), all(draw_quantiles <= 
                                              1))
    quantiles <- ggplot2:::create_quantile_segment_frame(data, draw_quantiles)
    aesthetics <- data[rep(1, nrow(quantiles)), setdiff(names(data), c("x", "y")), drop = FALSE]
    aesthetics$alpha <- rep(1, nrow(quantiles))
    both <- cbind(quantiles, aesthetics)
    quantile_grob <- GeomPath$draw_panel(both, ...)
    ggplot2:::ggname("geom_split_violin", grid::grobTree(GeomPolygon$draw_panel(newdata, ...), quantile_grob))
  }
  else {
    ggplot2:::ggname("geom_split_violin", GeomPolygon$draw_panel(newdata, ...))
  }
})

geom_split_violin <- function (mapping = NULL, data = NULL, stat = "ydensity", position = "identity", ..., draw_quantiles = NULL, trim = TRUE, scale = "area", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {
  layer(data = data, mapping = mapping, stat = stat, geom = GeomSplitViolin, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list(trim = trim, scale = scale, draw_quantiles = draw_quantiles, na.rm = na.rm, ...))
}

scatter 比较 fig.3 DCN 和 LUM 在 FbM 中 sup vs unsup

ds2 -> ds0

bst_model <- readRDS("ds2_model.rds")
ds2_data <- get_data_table(ds2, highvar = F, type = "data")
Idents(ds2) <- ds2$seurat_clusters
Idents(ds0) <- ds0$seurat_clusters
temp <- get_data_table(ds0, highvar = F, type = "data")
ds0_data <- matrix(data=0, nrow = length(rownames(ds2_data)), ncol = length(colnames(temp)), 
                   byrow = FALSE, dimnames = list(rownames(ds2_data),colnames(temp)))
for(i in intersect(rownames(ds2_data), rownames(temp))){
  ds0_data[i,] <- temp[i,]
}
rm(temp)
ds0_label <- as.numeric(as.character(Idents(ds0)))
colnames(ds0_data) <- NULL
ds0_test_data <- list(data = t(as(ds0_data,"dgCMatrix")), label = ds0_label)
ds0_test <- xgb.DMatrix(data = ds0_test_data$data,label = ds0_test_data$label)

#预测结果
predict_ds0_test <- predict(bst_model, newdata = ds0_test)
predict_prop_ds0 <- matrix(data=predict_ds0_test, nrow = length(levels(Idents(ds2))), 
                           ncol = ncol(ds0), byrow = FALSE, 
                           dimnames = list(levels(Idents(ds2)),colnames(ds0)))

## 得到分群结果
ds0_res <- apply(predict_prop_ds0,2,func,rownames(predict_prop_ds0))
Idents(ds0) <- factor(ds0_res,levels = c(0:4))
umapplot(ds0)
ds0$supclustering <- Idents(ds0) #保存监督聚类结果
Idents(ds0) <- ds0$supclustering
sup_ds0FBM <- subset(ds0, ident = "1")
Idents(ds0) <- ds0$Classification1
unsup_ds0FBM <- subset(ds0, ident = "Fibromyocyte")
ref_unsup_ds2FBM <- subset(ds2, ident = "1")

data1 <- FetchData(object = sup_ds0FBM, vars = c("LUM", "ACTA2","BGN","TAGLN"))
rownames(data1) <-  NULL
data1$group <- "sup"

data2 <- FetchData(object = unsup_ds0FBM, vars = c("LUM", "ACTA2","BGN","TAGLN"))
rownames(data2) <-  NULL
data2$group <- "unsup"

data3 <- FetchData(object = ref_unsup_ds2FBM, vars = c("LUM", "ACTA2","BGN","TAGLN"))
rownames(data3) <-  NULL
data3$group <- "ref"

data <- rbind(data1,data2,data3)

ggplot(data, aes(x=LUM, y=BGN, color = group, group = group)) +
  geom_point(size = 3,alpha = 0.1) + 
  geom_smooth(method=lm , se=TRUE) +
  theme_classic() +  theme(axis.title = element_text(size = 20,color = "black"),
        axis.text = element_text(size = 20,color = "black"),
        axis.line = element_line(size = 1),
        axis.ticks = element_line(size = 1),
        title = element_text(size = 20))
`geom_smooth()` using formula 'y ~ x'

ggplot(data, aes(x=LUM, y=ACTA2, color = group, group = group)) +
  geom_point(size = 3,alpha = 0.1) + 
  geom_smooth(method=lm , se=TRUE) +
  theme_classic() +  theme(axis.title = element_text(size = 20,color = "black"),
        axis.text = element_text(size = 20,color = "black"),
        axis.line = element_line(size = 1),
        axis.ticks = element_line(size = 1),
        title = element_text(size = 20))
`geom_smooth()` using formula 'y ~ x'

ggplot(data, aes(x=TAGLN, y=ACTA2, color = group, group = group)) +
  geom_point(size = 3,alpha = 0.1) + 
  geom_smooth(method=lm , se=TRUE) +
  theme_classic() +  theme(axis.title = element_text(size = 20,color = "black"),
        axis.text = element_text(size = 20,color = "black"),
        axis.line = element_line(size = 1),
        axis.ticks = element_line(size = 1),
        title = element_text(size = 20))
`geom_smooth()` using formula 'y ~ x'

scatter 比较 fig.3 DCN 和 LUM 在 FbM 中 sup vs unsup

ds2 -> ds1

Idents(ds1) <- ds1$supclustering
sup_ds1FBM <- subset(ds1, ident = "1")
Idents(ds1) <- ds1$Classification1
unsup_ds1FBM <- subset(ds1, ident = "Fibromyocyte")
ref_unsup_ds2FBM <- subset(ds2, ident = "1")

data1 <- FetchData(object = sup_ds1FBM, vars = c("LUM", "ACTA2","BGN","TAGLN"))
rownames(data1) <-  NULL
data1$group <- "sup"

data2 <- FetchData(object = unsup_ds1FBM, vars = c("LUM", "ACTA2","BGN","TAGLN"))
rownames(data2) <-  NULL
data2$group <- "unsup"

data3 <- FetchData(object = ref_unsup_ds2FBM, vars = c("LUM", "ACTA2","BGN","TAGLN"))
rownames(data3) <-  NULL
data3$group <- "ref"

data <- rbind(data1,data2,data3)

ggplot(data, aes(x=LUM, y=BGN, color = group, group = group)) +
  geom_point(size = 3,alpha = 0.1) + 
  geom_smooth(method=lm , se=TRUE) +
  theme_classic() +  theme(axis.title = element_text(size = 20,color = "black"),
        axis.text = element_text(size = 20,color = "black"),
        axis.line = element_line(size = 1),
        axis.ticks = element_line(size = 1),
        title = element_text(size = 20))
`geom_smooth()` using formula 'y ~ x'

ggplot(data, aes(x=LUM, y=ACTA2, color = group, group = group)) +
  geom_point(size = 3,alpha = 0.1) + 
  geom_smooth(method=lm , se=TRUE) +
  theme_classic() +  theme(axis.title = element_text(size = 20,color = "black"),
        axis.text = element_text(size = 20,color = "black"),
        axis.line = element_line(size = 1),
        axis.ticks = element_line(size = 1),
        title = element_text(size = 20))
`geom_smooth()` using formula 'y ~ x'

ggplot(data, aes(x=TAGLN, y=ACTA2, color = group, group = group)) +
  geom_point(size = 3,alpha = 0.1) + 
  geom_smooth(method=lm , se=TRUE) +
  theme_classic() +  theme(axis.title = element_text(size = 20,color = "black"),
        axis.text = element_text(size = 20,color = "black"),
        axis.line = element_line(size = 1),
        axis.ticks = element_line(size = 1),
        title = element_text(size = 20))
`geom_smooth()` using formula 'y ~ x'

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ3RybCtTaGlmdCtFbnRlciouIAoKYGBge3J9CnNvdXJjZSgidGlhbmZlbmdSd3JhcHBlcnMuUiIpCmBgYApgYGB7cn0KZHMyIDwtIHJlYWRSRFMoImRzMi5yZHMiKQpgYGAKCiMgdW1hcHBsb3QKYGBge3J9CnVtYXBwbG90KGRzMikKZHMyIDwtIFJlbmFtZUlkZW50cyhkczIsIkZCIiA9ICJGaWJyb2JsYXN0IiwgInBlcmljeXRlIiA9ICJQZXJpY3l0ZSIsImZpYnJvbXlvY3l0ZSI9IkZpYnJvbXlvY3l0ZSIpCnVtYXBwbG90KGRzMiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIikKSWRlbnRzKGRzMikgPC0gZmFjdG9yKElkZW50cyhkczIpLGxldmVscyA9IGMoIlNNQzEiLCJGaWJyb215b2N5dGUiLCJQZXJpY3l0ZSIsIkZpYnJvYmxhc3QiLCJTTUMyIikpCnVtYXBwbG90KGRzMikKZHMyJENsYXNzaWZpY2F0aW9uMSA8LSBJZGVudHMoZHMyKQpzYXZlUkRTKGRzMiwiZHMyLnJkcyIpCgpnZ3NhdmUoIi4vZmlnMy9kczIuc3ZnIixwbG90ID0gdW1hcHBsb3QoZHMyKSxkZXZpY2UgPSBzdmcsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKYGBgCgpgYGB7cn0KZHMwIDwtIHJlYWRSRFMoImRzMC5yZHMiKQpgYGAKCiMg5ZGo57uG6IOe55qE5a2Y5ZyoCmBgYHtyIGZpZy53aWR0aD02LGZpZy5oZWlnaHQ9Nn0KCmdnc2F2ZSgiLi9maWczL2RzMC5zdmciLHBsb3QgPSB1bWFwcGxvdChkczApLGRldmljZSA9IHN2Zywgd2lkdGggPSA3LCBoZWlnaHQgPSA1KQoKIyMgcGVyaWN5dGUKbXVsdGlfZmVhdHVyZXBsb3QoYygiRkFCUDQiLCAiUkVSR0wiLCAiTlJJUDIiLCJISUdEMUIiKSxkczIsbGFiZWxzID0gIiIpCmBgYAoKYGBge3J9CmxpYnJhcnkoaWdyYXBoKQpgYGAKCmBgYHtyfQpkczFfZXhwciA8LSBnZXRfYXZlcmV4cHJfbWF0X2NsdXN0ZXIoZHMxKQpjbHVzdGVyX2luZm8gPC0gZGF0YS5mcmFtZShjb2xuYW1lcyhkczFfZXhwciksIjEiLGNoZWNrLm5hbWVzID0gRikKCmRzMl9leHByIDwtIGdldF9hdmVyZXhwcl9tYXRfY2x1c3RlcihkczIpCmNsdXN0ZXJfaW5mbzIgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyhkczJfZXhwciksIjIiLGNoZWNrLm5hbWVzID0gRikKCnNlbGVjdGVkX2dlbmVzIDwtIGludGVyc2VjdChkczJAYXNzYXlzW1siU0NUIl1dQHZhci5mZWF0dXJlcyxkczFAYXNzYXlzW1siU0NUIl1dQHZhci5mZWF0dXJlcykKZHMyX2V4cHIgPC0gZHMyX2V4cHJbc2VsZWN0ZWRfZ2VuZXMsXQpkczFfZXhwciA8LSBkczFfZXhwcltzZWxlY3RlZF9nZW5lcyxdCmV4cHIgPC0gY2JpbmQoZHMxX2V4cHIsZHMyX2V4cHIpCmNvcnJfbWF0IDwtIGNvcihleHByKQoKY29sX2Z1biA8LSAgY29sb3JSYW1wMihjKDAuNywgMC44NSwgMSksIGMoIiMxRTkwRkYiLCAid2hpdGUiLCAiI2ZmMjEyMSIpKQpIZWF0bWFwKGNvcnJfbWF0LCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHVtbnMgPSBULCAKICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IFQsIHNob3dfcm93X25hbWVzID0gVCwKIGNvbHVtbl90aXRsZSA9IE5VTEwsCiBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoCiB0aXRsZT0nQ29yJywgdGl0bGVfcG9zaXRpb249J2xlZnRjZW50ZXItcm90JyksIGNvbCA9IGNvbF9mdW4pCmBgYAoKIyMg5Z+65Zug6KGo6L6+CmRzMiAtPiBkczEK5peg55uR552j6IGa57G7CmBgYHtyfQpkczEgPC0gcmVhZFJEUygiZHMxLnJkcyIpCmRzMkZiTSA8LSBzdWJzZXQoZHMyLGlkZW50ID0gIkZpYnJvbXlvY3l0ZSIpCmRzMUZiTSA8LSBzdWJzZXQoZHMxLGlkZW50ID0gIkZpYnJvbXlvY3l0ZSIpCgpkczJkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMkZiTSx0eXBlID0gImRhdGEiKQpkczFkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMUZiTSx0eXBlID0gImRhdGEiKQoKIyBkczJleHByIDwtIGRhdGEuZnJhbWUoZXhwciA9IGRzMmRhdGFbIkRDTiIsXSwgc2FtcGxlID0gImRzMiIsIGdlbmUgPSAiRENOIikKIyByb3duYW1lcyhkczJleHByKSA8LSBOVUxMCiMgZHMxZXhwciA8LSBkYXRhLmZyYW1lKGV4cHIgPSBkczFkYXRhWyJEQ04iLF0sIHNhbXBsZSA9ICJkczEiKQojIHJvd25hbWVzKGRzMWV4cHIpIDwtIE5VTEwKIyBtZXJnZV9leHByIDwtIHJiaW5kKGRzMmV4cHIsZHMxZXhwcikKCmdlbmVzX3RvX3Nob3cgPC0gYygiRENOIiwiTFVNIiwiTU1QMiIsIkFDVEEyIiwiVE5GUlNGMTFCIiwiRkJMTjEiKQoKZnVuYzEgPC0gZnVuY3Rpb24oZ2VuZSwgc2FtcGxlLCBkYXRhYmxlKXsKICBkYXRhLmZyYW1lKGV4cHIgPSBkYXRhYmxlW2dlbmUsXSwgc2FtcGxlID0gc2FtcGxlLCBnZW5lID0gZ2VuZSkKfQoKbWVyZ2VfZXhwciA8LSBkYXRhLmZyYW1lKCkKCmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYzEsImRzMSIsZHMxZGF0YSkpCnsKICBtZXJnZV9leHByIDwtIHJiaW5kKG1lcmdlX2V4cHIsaSkKfQpmb3IgKGkgaW4gbGFwcGx5KGdlbmVzX3RvX3Nob3csIGZ1bmMxLCJkczIiLGRzMmRhdGEpKQp7CiAgbWVyZ2VfZXhwciA8LSByYmluZChtZXJnZV9leHByLGkpCn0KCgpyb3duYW1lcyhtZXJnZV9leHByKSA8LSBOVUxMCgoKCkRhdGFfc3VtbWFyeSA8LSBSbWlzYzo6c3VtbWFyeVNFKG1lcmdlX2V4cHIsIG1lYXN1cmV2YXI9ImV4cHIiLCBncm91cHZhcnM9Yygic2FtcGxlIiwiZ2VuZSIpKQpoZWFkKERhdGFfc3VtbWFyeSkKCmdnb2JqIDwtIGdncGxvdChtZXJnZV9leHByLGFlcyh4ID0gZ2VuZSwgeSA9IGV4cHIsZmlsbCA9IHNhbXBsZSkpICsKICBnZW9tX3NwbGl0X3Zpb2xpbih0cmltPSBGLCBjb2xvcj0id2hpdGUiLCBzY2FsZSA9ICJhcmVhIikgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBEYXRhX3N1bW1hcnksYWVzKHggPSBnZW5lLCB5PSBleHByKSwgcGNoPTE5LAogICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMC4yKSxzaXplPSAxKSArICPnu5jliLblnYflgLzkvY3nva4KICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBEYXRhX3N1bW1hcnksIGFlcyh5bWluID0gZXhwci1jaSwgeW1heD0gZXhwcitjaSksIAogICAgICAgICAgICAgICAgd2lkdGg9IDAuMDUsIAogICAgICAgICAgICAgICAgcG9zaXRpb249IHBvc2l0aW9uX2RvZGdlKDAuMiksICPor6/lt67nur/kvY3nva7vvIzlkozlnYflgLzkvY3nva7nm7jljLnphY0KICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNywKICAgICAgICAgICAgICAgIHNpemU9IDAuNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNiMWQ2ZmIiLCAiI2ZkOTk5OSIpKSsgCiAgbGFicyh5PSgiTG9nMiBleHByZXNzaW9uIikseD1OVUxMLHRpdGxlID0gIlNwbGl0IHZpb2xpbiIpICsgCiAgdGhlbWVfY2xhc3NpYygpKyBteXRoZW1lICsgc3RhdF9jb21wYXJlX21lYW5zKGFlcyhncm91cCA9IHNhbXBsZSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gInAuZm9ybWF0IiwKICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIndpbGNveC50ZXN0IiwKICAgICAgICAgICAgICAgICAgICAgbGFiZWwueSA9IG1heChtZXJnZV9leHByJGV4cHIpLAogICAgICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IEYpCmdnc2F2ZSgidW5kczJ0b2RzMS5zdmciLCBkZXZpY2UgPSBzdmcsIHBsb3QgPSBnZ29iaiwgaGVpZ2h0ID0gNiwgd2lkdGggPSAxMCkKCmBgYAojIOebkeedo+iBmuexu+e7k+aenAojIyDov5nph4zkvb/nlKhudW1lcmlj55qE5YiG576kCmBgYHtyfQpkczJGYk0gPC0gc3Vic2V0KGRzMixpZGVudCA9ICIxIikKZHMxRmJNIDwtIHN1YnNldChkczEsaWRlbnQgPSAiMSIpCgpkczJkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMkZiTSx0eXBlID0gImRhdGEiKQpkczFkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMUZiTSx0eXBlID0gImRhdGEiKQoKIyBkczJleHByIDwtIGRhdGEuZnJhbWUoZXhwciA9IGRzMmRhdGFbIkRDTiIsXSwgc2FtcGxlID0gImRzMiIsIGdlbmUgPSAiRENOIikKIyByb3duYW1lcyhkczJleHByKSA8LSBOVUxMCiMgZHMxZXhwciA8LSBkYXRhLmZyYW1lKGV4cHIgPSBkczFkYXRhWyJEQ04iLF0sIHNhbXBsZSA9ICJkczEiKQojIHJvd25hbWVzKGRzMWV4cHIpIDwtIE5VTEwKIyBtZXJnZV9leHByIDwtIHJiaW5kKGRzMmV4cHIsZHMxZXhwcikKCmdlbmVzX3RvX3Nob3cgPC0gYygiRENOIiwiTFVNIiwiTU1QMiIsIkFDVEEyIiwiVE5GUlNGMTFCIiwiRkJMTjEiKQoKZnVuYzEgPC0gZnVuY3Rpb24oZ2VuZSwgc2FtcGxlLCBkYXRhYmxlKXsKICBkYXRhLmZyYW1lKGV4cHIgPSBkYXRhYmxlW2dlbmUsXSwgc2FtcGxlID0gc2FtcGxlLCBnZW5lID0gZ2VuZSkKfQoKbWVyZ2VfZXhwciA8LSBkYXRhLmZyYW1lKCkKCmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYzEsImRzMSIsZHMxZGF0YSkpCnsKICBtZXJnZV9leHByIDwtIHJiaW5kKG1lcmdlX2V4cHIsaSkKfQpmb3IgKGkgaW4gbGFwcGx5KGdlbmVzX3RvX3Nob3csIGZ1bmMxLCJkczIiLGRzMmRhdGEpKQp7CiAgbWVyZ2VfZXhwciA8LSByYmluZChtZXJnZV9leHByLGkpCn0KCgpyb3duYW1lcyhtZXJnZV9leHByKSA8LSBOVUxMCgpEYXRhX3N1bW1hcnkgPC0gUm1pc2M6OnN1bW1hcnlTRShtZXJnZV9leHByLCBtZWFzdXJldmFyPSJleHByIiwgZ3JvdXB2YXJzPWMoInNhbXBsZSIsImdlbmUiKSkKaGVhZChEYXRhX3N1bW1hcnkpCgpnZ29iaiA8LSBnZ3Bsb3QobWVyZ2VfZXhwcixhZXMoeCA9IGdlbmUsIHkgPSBleHByLGZpbGwgPSBzYW1wbGUpKSArCiAgZ2VvbV9zcGxpdF92aW9saW4odHJpbT0gRiwgY29sb3I9IndoaXRlIiwgc2NhbGUgPSAiYXJlYSIpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gRGF0YV9zdW1tYXJ5LGFlcyh4ID0gZ2VuZSwgeT0gZXhwciksIHBjaD0xOSwKICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuMiksc2l6ZT0gMSkgKyAj57uY5Yi25Z2H5YC85L2N572uCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gRGF0YV9zdW1tYXJ5LCBhZXMoeW1pbiA9IGV4cHItY2ksIHltYXg9IGV4cHIrY2kpLCAKICAgICAgICAgICAgICAgIHdpZHRoPSAwLjA1LCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uPSBwb3NpdGlvbl9kb2RnZSgwLjIpLCAj6K+v5beu57q/5L2N572u77yM5ZKM5Z2H5YC85L2N572u55u45Yy56YWNCiAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLAogICAgICAgICAgICAgICAgYWxwaGEgPSAwLjcsCiAgICAgICAgICAgICAgICBzaXplPSAwLjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYjFkNmZiIiwgIiNmZDk5OTkiKSkrIAogIGxhYnMoeT0oIkxvZzIgZXhwcmVzc2lvbiIpLHg9TlVMTCx0aXRsZSA9ICJTcGxpdCB2aW9saW4iKSArIAogIHRoZW1lX2NsYXNzaWMoKSsgbXl0aGVtZSArIHN0YXRfY29tcGFyZV9tZWFucyhhZXMoZ3JvdXAgPSBzYW1wbGUpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLmZvcm1hdCIsCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnkgPSBtYXgobWVyZ2VfZXhwciRleHByKSwKICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBGKQoKZ2dzYXZlKCJzdXBkczJ0b2RzMS5zdmciLCBkZXZpY2UgPSBzdmcsIHBsb3QgPSBnZ29iaiwgaGVpZ2h0ID0gNiwgd2lkdGggPSAxMCkKYGBgCgojIGRzMiAtPiBkczAKIyMg5peg55uR552j6IGa57G7CmBgYHtyfQpkczJGYk0gPC0gc3Vic2V0KGRzMixpZGVudCA9ICIxIikKZHMwRmJNIDwtIHN1YnNldChkczAsaWRlbnQgPSAiRmlicm9teW9jeXRlIikKCmRzMmRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMyRmJNLHR5cGUgPSAiZGF0YSIpCmRzMGRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMwRmJNLHR5cGUgPSAiZGF0YSIpCgpnZW5lc190b19zaG93IDwtIGMoIkRDTiIsIkxVTSIsIk1NUDIiLCJBQ1RBMiIsIlRORlJTRjExQiIsIkZCTE4xIikKCgptZXJnZV9leHByIDwtIGRhdGEuZnJhbWUoKQoKZm9yIChpIGluIGxhcHBseShnZW5lc190b19zaG93LCBmdW5jMSwiZHMwIixkczBkYXRhKSkKewogIG1lcmdlX2V4cHIgPC0gcmJpbmQobWVyZ2VfZXhwcixpKQp9CmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYzEsImRzMiIsZHMyZGF0YSkpCnsKICBtZXJnZV9leHByIDwtIHJiaW5kKG1lcmdlX2V4cHIsaSkKfQoKcm93bmFtZXMobWVyZ2VfZXhwcikgPC0gTlVMTAoKRGF0YV9zdW1tYXJ5IDwtIFJtaXNjOjpzdW1tYXJ5U0UobWVyZ2VfZXhwciwgbWVhc3VyZXZhcj0iZXhwciIsIGdyb3VwdmFycz1jKCJzYW1wbGUiLCJnZW5lIikpCmhlYWQoRGF0YV9zdW1tYXJ5KQoKZ2dvYmogPC0gZ2dwbG90KG1lcmdlX2V4cHIsYWVzKHggPSBnZW5lLCB5ID0gZXhwcixmaWxsID0gc2FtcGxlKSkgKwogIGdlb21fc3BsaXRfdmlvbGluKHRyaW09IEYsIGNvbG9yPSJ3aGl0ZSIsIHNjYWxlID0gImFyZWEiKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IERhdGFfc3VtbWFyeSxhZXMoeCA9IGdlbmUsIHk9IGV4cHIpLCBwY2g9MTksCiAgICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgwLjIpLHNpemU9IDEpICsgI+e7mOWItuWdh+WAvOS9jee9rgogIGdlb21fZXJyb3JiYXIoZGF0YSA9IERhdGFfc3VtbWFyeSwgYWVzKHltaW4gPSBleHByLWNpLCB5bWF4PSBleHByK2NpKSwgCiAgICAgICAgICAgICAgICB3aWR0aD0gMC4wNSwgCiAgICAgICAgICAgICAgICBwb3NpdGlvbj0gcG9zaXRpb25fZG9kZ2UoMC4yKSwgI+ivr+W3rue6v+S9jee9ru+8jOWSjOWdh+WAvOS9jee9ruebuOWMuemFjQogICAgICAgICAgICAgICAgY29sb3I9ImJsYWNrIiwKICAgICAgICAgICAgICAgIGFscGhhID0gMC43LAogICAgICAgICAgICAgICAgc2l6ZT0gMC41KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2IxZDZmYiIsICIjZmQ5OTk5IikpKyAKICBsYWJzKHk9KCJMb2cyIGV4cHJlc3Npb24iKSx4PU5VTEwsdGl0bGUgPSAiU3BsaXQgdmlvbGluIikgKyAKICB0aGVtZV9jbGFzc2ljKCkrIG15dGhlbWUgKyBzdGF0X2NvbXBhcmVfbWVhbnMoYWVzKGdyb3VwID0gc2FtcGxlKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5mb3JtYXQiLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC55ID0gbWF4KG1lcmdlX2V4cHIkZXhwciksCiAgICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gRikKCmdnc2F2ZSgidW5kczJ0b2RzMC5zdmciLCBkZXZpY2UgPSBzdmcsIHBsb3QgPSBnZ29iaiwgaGVpZ2h0ID0gNiwgd2lkdGggPSAxMCkKYGBgCgojIyDnm5HnnaPogZrnsbsKCmBgYHtyfQpJZGVudHMoZHMwKSA8LSBkczAkc3VwY2x1c3RlcmluZwpkczJGYk0gPC0gc3Vic2V0KGRzMixpZGVudCA9ICIxIikKZHMwRmJNIDwtIHN1YnNldChkczAsaWRlbnQgPSAiMSIpCgpkczJkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMkZiTSx0eXBlID0gImRhdGEiKQpkczBkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMEZiTSx0eXBlID0gImRhdGEiKQoKZ2VuZXNfdG9fc2hvdyA8LSBjKCJEQ04iLCJMVU0iLCJNTVAyIiwiQUNUQTIiLCJUTkZSU0YxMUIiLCJGQkxOMSIpCgptZXJnZV9leHByIDwtIGRhdGEuZnJhbWUoKQoKZm9yIChpIGluIGxhcHBseShnZW5lc190b19zaG93LCBmdW5jMSwiZHMwIixkczBkYXRhKSkKewogIG1lcmdlX2V4cHIgPC0gcmJpbmQobWVyZ2VfZXhwcixpKQp9CmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYzEsImRzMiIsZHMyZGF0YSkpCnsKICBtZXJnZV9leHByIDwtIHJiaW5kKG1lcmdlX2V4cHIsaSkKfQoKcm93bmFtZXMobWVyZ2VfZXhwcikgPC0gTlVMTAoKRGF0YV9zdW1tYXJ5IDwtIFJtaXNjOjpzdW1tYXJ5U0UobWVyZ2VfZXhwciwgbWVhc3VyZXZhcj0iZXhwciIsIGdyb3VwdmFycz1jKCJzYW1wbGUiLCJnZW5lIikpCmhlYWQoRGF0YV9zdW1tYXJ5KQoKZ2dvYmogPC0gZ2dwbG90KG1lcmdlX2V4cHIsYWVzKHggPSBnZW5lLCB5ID0gZXhwcixmaWxsID0gc2FtcGxlKSkgKwogIGdlb21fc3BsaXRfdmlvbGluKHRyaW09IEYsIGNvbG9yPSJ3aGl0ZSIsIHNjYWxlID0gImFyZWEiKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IERhdGFfc3VtbWFyeSxhZXMoeCA9IGdlbmUsIHk9IGV4cHIpLCBwY2g9MTksCiAgICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgwLjIpLHNpemU9IDEpICsgI+e7mOWItuWdh+WAvOS9jee9rgogIGdlb21fZXJyb3JiYXIoZGF0YSA9IERhdGFfc3VtbWFyeSwgYWVzKHltaW4gPSBleHByLWNpLCB5bWF4PSBleHByK2NpKSwgCiAgICAgICAgICAgICAgICB3aWR0aD0gMC4wNSwgCiAgICAgICAgICAgICAgICBwb3NpdGlvbj0gcG9zaXRpb25fZG9kZ2UoMC4yKSwgI+ivr+W3rue6v+S9jee9ru+8jOWSjOWdh+WAvOS9jee9ruebuOWMuemFjQogICAgICAgICAgICAgICAgY29sb3I9ImJsYWNrIiwKICAgICAgICAgICAgICAgIGFscGhhID0gMC43LAogICAgICAgICAgICAgICAgc2l6ZT0gMC41KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2IxZDZmYiIsICIjZmQ5OTk5IikpKyAKICBsYWJzKHk9KCJMb2cyIGV4cHJlc3Npb24iKSx4PU5VTEwsdGl0bGUgPSAiU3BsaXQgdmlvbGluIikgKyAKICB0aGVtZV9jbGFzc2ljKCkrIG15dGhlbWUgKyBzdGF0X2NvbXBhcmVfbWVhbnMoYWVzKGdyb3VwID0gc2FtcGxlKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5mb3JtYXQiLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC55ID0gbWF4KG1lcmdlX2V4cHIkZXhwciksCiAgICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gRikKCmdnc2F2ZSgic3VwZHMydG9kczAuc3ZnIiwgZGV2aWNlID0gc3ZnLCBwbG90ID0gZ2dvYmosIGhlaWdodCA9IDYsIHdpZHRoID0gMTApCmBgYAoKIyBkczAgLT4gZHMyCiMj5peg55uR552j6IGa57G7CmBgYHtyfQpkczIgPC0gcmVhZFJEUygiZHMyLnJkcyIpCklkZW50cyhkczApIDwtIGRzMCRDbGFzc2lmaWNhdGlvbjEKZHMyRmJNIDwtIHN1YnNldChkczIsaWRlbnQgPSAiRmlicm9teW9jeXRlIikKZHMwRmJNIDwtIHN1YnNldChkczAsaWRlbnQgPSAiRmlicm9teW9jeXRlIikKCmRzMmRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMyRmJNLHR5cGUgPSAiZGF0YSIpCmRzMGRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMwRmJNLHR5cGUgPSAiZGF0YSIpCgojIGdlbmVzX3RvX3Nob3cgPC0gYygiSUdGQlAyIiwiTUdQIiwiTVlIMTEiLCJEQ04iLCJUTkZSU0YxMUIiKQpnZW5lc190b19zaG93IDwtIGMoIkRDTiIsIkxVTSIsIk1NUDIiLCJBQ1RBMiIsIlRORlJTRjExQiIsIkZCTE4xIikKCgoKbWVyZ2VfZXhwciA8LSBkYXRhLmZyYW1lKCkKCmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYzEsImRzMCIsZHMwZGF0YSkpCnsKICBtZXJnZV9leHByIDwtIHJiaW5kKG1lcmdlX2V4cHIsaSkKfQpmb3IgKGkgaW4gbGFwcGx5KGdlbmVzX3RvX3Nob3csIGZ1bmMxLCJkczIiLGRzMmRhdGEpKQp7CiAgbWVyZ2VfZXhwciA8LSByYmluZChtZXJnZV9leHByLGkpCn0KCnJvd25hbWVzKG1lcmdlX2V4cHIpIDwtIE5VTEwKCkRhdGFfc3VtbWFyeSA8LSBSbWlzYzo6c3VtbWFyeVNFKG1lcmdlX2V4cHIsIG1lYXN1cmV2YXI9ImV4cHIiLCBncm91cHZhcnM9Yygic2FtcGxlIiwiZ2VuZSIpKQpoZWFkKERhdGFfc3VtbWFyeSkKCmdnb2JqIDwtIGdncGxvdChtZXJnZV9leHByLGFlcyh4ID0gZ2VuZSwgeSA9IGV4cHIsZmlsbCA9IHNhbXBsZSkpICsKICBnZW9tX3NwbGl0X3Zpb2xpbih0cmltPSBGLCBjb2xvcj0id2hpdGUiLCBzY2FsZSA9ICJhcmVhIikgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBEYXRhX3N1bW1hcnksYWVzKHggPSBnZW5lLCB5PSBleHByKSwgcGNoPTE5LAogICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMC4yKSxzaXplPSAxKSArICPnu5jliLblnYflgLzkvY3nva4KICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBEYXRhX3N1bW1hcnksIGFlcyh5bWluID0gZXhwci1jaSwgeW1heD0gZXhwcitjaSksIAogICAgICAgICAgICAgICAgd2lkdGg9IDAuMDUsIAogICAgICAgICAgICAgICAgcG9zaXRpb249IHBvc2l0aW9uX2RvZGdlKDAuMiksICPor6/lt67nur/kvY3nva7vvIzlkozlnYflgLzkvY3nva7nm7jljLnphY0KICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNywKICAgICAgICAgICAgICAgIHNpemU9IDAuNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNiMWQ2ZmIiLCAiI2ZkOTk5OSIpKSsgCiAgbGFicyh5PSgiTG9nMiBleHByZXNzaW9uIikseD1OVUxMLHRpdGxlID0gIlNwbGl0IHZpb2xpbiIpICsgCiAgdGhlbWVfY2xhc3NpYygpKyBteXRoZW1lICsgc3RhdF9jb21wYXJlX21lYW5zKGFlcyhncm91cCA9IHNhbXBsZSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gInAuZm9ybWF0IiwKICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIndpbGNveC50ZXN0IiwKICAgICAgICAgICAgICAgICAgICAgbGFiZWwueSA9IG1heChtZXJnZV9leHByJGV4cHIpLAogICAgICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IEYpCgpnZ3NhdmUoIjJfdW5kczB0b2RzMi5zdmciLCBkZXZpY2UgPSBzdmcsIHBsb3QgPSBnZ29iaiwgaGVpZ2h0ID0gNiwgd2lkdGggPSAxMCkKYGBgCgojIyDnm5HnnaPogZrnsbsKZHMwIC0+IGRzMgpgYGB7cn0KCmRzMkZiTSA8LSBzdWJzZXQoZHMyLGlkZW50ID0gIjIiKQpkczBGYk0gPC0gc3Vic2V0KGRzMCxpZGVudCA9ICIyIikKCmRzMmRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMyRmJNLHR5cGUgPSAiZGF0YSIpCmRzMGRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMwRmJNLHR5cGUgPSAiZGF0YSIpCgpnZW5lc190b19zaG93IDwtIGMoIklHRkJQMiIsIk1HUCIsIk1ZSDExIiwiRENOIiwiVE5GUlNGMTFCIikKIyBnZW5lc190b19zaG93IDwtIGMoIkRDTiIsIkxVTSIsIk1NUDIiLCJBQ1RBMiIsIlRORlJTRjExQiIsIkZCTE4xIikKCm1lcmdlX2V4cHIgPC0gZGF0YS5mcmFtZSgpCgpmb3IgKGkgaW4gbGFwcGx5KGdlbmVzX3RvX3Nob3csIGZ1bmMxLCJkczAiLGRzMGRhdGEpKQp7CiAgbWVyZ2VfZXhwciA8LSByYmluZChtZXJnZV9leHByLGkpCn0KZm9yIChpIGluIGxhcHBseShnZW5lc190b19zaG93LCBmdW5jMSwiZHMyIixkczJkYXRhKSkKewogIG1lcmdlX2V4cHIgPC0gcmJpbmQobWVyZ2VfZXhwcixpKQp9Cgpyb3duYW1lcyhtZXJnZV9leHByKSA8LSBOVUxMCgpEYXRhX3N1bW1hcnkgPC0gUm1pc2M6OnN1bW1hcnlTRShtZXJnZV9leHByLCBtZWFzdXJldmFyPSJleHByIiwgZ3JvdXB2YXJzPWMoInNhbXBsZSIsImdlbmUiKSkKaGVhZChEYXRhX3N1bW1hcnkpCgpnZ29iaiA8LSBnZ3Bsb3QobWVyZ2VfZXhwcixhZXMoeCA9IGdlbmUsIHkgPSBleHByLGZpbGwgPSBzYW1wbGUpKSArCiAgZ2VvbV9zcGxpdF92aW9saW4odHJpbT0gRiwgY29sb3I9IndoaXRlIiwgc2NhbGUgPSAiYXJlYSIpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gRGF0YV9zdW1tYXJ5LGFlcyh4ID0gZ2VuZSwgeT0gZXhwciksIHBjaD0xOSwKICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuMiksc2l6ZT0gMSkgKyAj57uY5Yi25Z2H5YC85L2N572uCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gRGF0YV9zdW1tYXJ5LCBhZXMoeW1pbiA9IGV4cHItY2ksIHltYXg9IGV4cHIrY2kpLCAKICAgICAgICAgICAgICAgIHdpZHRoPSAwLjA1LCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uPSBwb3NpdGlvbl9kb2RnZSgwLjIpLCAj6K+v5beu57q/5L2N572u77yM5ZKM5Z2H5YC85L2N572u55u45Yy56YWNCiAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLAogICAgICAgICAgICAgICAgYWxwaGEgPSAwLjcsCiAgICAgICAgICAgICAgICBzaXplPSAwLjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYjFkNmZiIiwgIiNmZDk5OTkiKSkrIAogIGxhYnMoeT0oIkxvZzIgZXhwcmVzc2lvbiIpLHg9TlVMTCx0aXRsZSA9ICJTcGxpdCB2aW9saW4iKSArIAogIHRoZW1lX2NsYXNzaWMoKSsgbXl0aGVtZSArIHN0YXRfY29tcGFyZV9tZWFucyhhZXMoZ3JvdXAgPSBzYW1wbGUpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLmZvcm1hdCIsCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnkgPSBtYXgobWVyZ2VfZXhwciRleHByKSwKICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBGKQpnZ29iagpnZ3NhdmUoInN1cGRzMHRvZHMyLnN2ZyIsIGRldmljZSA9IHN2ZywgcGxvdCA9IGdnb2JqLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEwKQpgYGAKCgoKIyBkczAgLT4gZHMxCiMj5peg55uR552j6IGa57G7CmBgYHtyfQpJZGVudHMoZHMxKSA8LSBkczEkQ2xhc3NpZmljYXRpb24xCklkZW50cyhkczApIDwtIGRzMCRDbGFzc2lmaWNhdGlvbjEKZHMxRmJNIDwtIHN1YnNldChkczEsaWRlbnQgPSAiRmlicm9teW9jeXRlIikKZHMwRmJNIDwtIHN1YnNldChkczAsaWRlbnQgPSAiRmlicm9teW9jeXRlIikKCmRzMWRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMxRmJNLHR5cGUgPSAiZGF0YSIpCmRzMGRhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMwRmJNLHR5cGUgPSAiZGF0YSIpCgojIGdlbmVzX3RvX3Nob3cgPC0gYygiSUdGQlAyIiwiTUdQIiwiTVlIMTEiLCJEQ04iLCJUTkZSU0YxMUIiKQpnZW5lc190b19zaG93IDwtIGMoIkRDTiIsIkxVTSIsIk1NUDIiLCJBQ1RBMiIsIlRORlJTRjExQiIsIkZCTE4xIikKCmZ1bmMgPC0gZnVuY3Rpb24oZ2VuZSwgc2FtcGxlLCBkYXRhYmxlKXsKICBkYXRhLmZyYW1lKGV4cHIgPSBkYXRhYmxlW2dlbmUsXSwgc2FtcGxlID0gc2FtcGxlLCBnZW5lID0gZ2VuZSkKfQoKbWVyZ2VfZXhwciA8LSBkYXRhLmZyYW1lKCkKCmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYywiZHMwIixkczBkYXRhKSkKewogIG1lcmdlX2V4cHIgPC0gcmJpbmQobWVyZ2VfZXhwcixpKQp9CmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYywiZHMxIixkczFkYXRhKSkKewogIG1lcmdlX2V4cHIgPC0gcmJpbmQobWVyZ2VfZXhwcixpKQp9Cgpyb3duYW1lcyhtZXJnZV9leHByKSA8LSBOVUxMCgpEYXRhX3N1bW1hcnkgPC0gUm1pc2M6OnN1bW1hcnlTRShtZXJnZV9leHByLCBtZWFzdXJldmFyPSJleHByIiwgZ3JvdXB2YXJzPWMoInNhbXBsZSIsImdlbmUiKSkKaGVhZChEYXRhX3N1bW1hcnkpCgpnZ29iaiA8LSBnZ3Bsb3QobWVyZ2VfZXhwcixhZXMoeCA9IGdlbmUsIHkgPSBleHByLGZpbGwgPSBzYW1wbGUpKSArCiAgZ2VvbV9zcGxpdF92aW9saW4odHJpbT0gRiwgY29sb3I9IndoaXRlIiwgc2NhbGUgPSAiYXJlYSIpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gRGF0YV9zdW1tYXJ5LGFlcyh4ID0gZ2VuZSwgeT0gZXhwciksIHBjaD0xOSwKICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuMiksc2l6ZT0gMSkgKyAj57uY5Yi25Z2H5YC85L2N572uCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gRGF0YV9zdW1tYXJ5LCBhZXMoeW1pbiA9IGV4cHItY2ksIHltYXg9IGV4cHIrY2kpLCAKICAgICAgICAgICAgICAgIHdpZHRoPSAwLjA1LCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uPSBwb3NpdGlvbl9kb2RnZSgwLjIpLCAj6K+v5beu57q/5L2N572u77yM5ZKM5Z2H5YC85L2N572u55u45Yy56YWNCiAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLAogICAgICAgICAgICAgICAgYWxwaGEgPSAwLjcsCiAgICAgICAgICAgICAgICBzaXplPSAwLjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYjFkNmZiIiwgIiNmZDk5OTkiKSkrIAogIGxhYnMoeT0oIkxvZzIgZXhwcmVzc2lvbiIpLHg9TlVMTCx0aXRsZSA9ICJTcGxpdCB2aW9saW4iKSArIAogIHRoZW1lX2NsYXNzaWMoKSsgbXl0aGVtZSArIHN0YXRfY29tcGFyZV9tZWFucyhhZXMoZ3JvdXAgPSBzYW1wbGUpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLmZvcm1hdCIsCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnkgPSBtYXgobWVyZ2VfZXhwciRleHByKSwKICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBGKQpnZ29iagpnZ3NhdmUoIjJfdW5kczB0b2RzMS5zdmciLCBkZXZpY2UgPSBzdmcsIHBsb3QgPSBnZ29iaiwgaGVpZ2h0ID0gNiwgd2lkdGggPSAxMCkKYGBgCgojIyDnm5HnnaPogZrnsbsKZHMwIC0+IGRzMQpgYGB7cn0KSWRlbnRzKGRzMCkgPC0gZHMwJHNldXJhdF9jbHVzdGVycwpkczFGYk0gPC0gc3Vic2V0KGRzMSxpZGVudCA9ICIyIikKZHMwRmJNIDwtIHN1YnNldChkczAsaWRlbnQgPSAiMiIpCgpkczFkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMUZiTSx0eXBlID0gImRhdGEiKQpkczBkYXRhIDwtIGdldF9kYXRhX3RhYmxlKGRzMEZiTSx0eXBlID0gImRhdGEiKQoKIyBnZW5lc190b19zaG93IDwtIGMoIklHRkJQMiIsIk1HUCIsIk1ZSDExIiwiRENOIiwiVE5GUlNGMTFCIikKZ2VuZXNfdG9fc2hvdyA8LSBjKCJEQ04iLCJMVU0iLCJNTVAyIiwiQUNUQTIiLCJUTkZSU0YxMUIiLCJGQkxOMSIpCgptZXJnZV9leHByIDwtIGRhdGEuZnJhbWUoKQoKZm9yIChpIGluIGxhcHBseShnZW5lc190b19zaG93LCBmdW5jMSwiZHMwIixkczBkYXRhKSkKewogIG1lcmdlX2V4cHIgPC0gcmJpbmQobWVyZ2VfZXhwcixpKQp9CmZvciAoaSBpbiBsYXBwbHkoZ2VuZXNfdG9fc2hvdywgZnVuYzEsImRzMSIsZHMxZGF0YSkpCnsKICBtZXJnZV9leHByIDwtIHJiaW5kKG1lcmdlX2V4cHIsaSkKfQoKcm93bmFtZXMobWVyZ2VfZXhwcikgPC0gTlVMTAoKRGF0YV9zdW1tYXJ5IDwtIFJtaXNjOjpzdW1tYXJ5U0UobWVyZ2VfZXhwciwgbWVhc3VyZXZhcj0iZXhwciIsIGdyb3VwdmFycz1jKCJzYW1wbGUiLCJnZW5lIikpCmhlYWQoRGF0YV9zdW1tYXJ5KQoKZ2dvYmogPC0gZ2dwbG90KG1lcmdlX2V4cHIsYWVzKHggPSBnZW5lLCB5ID0gZXhwcixmaWxsID0gc2FtcGxlKSkgKwogIGdlb21fc3BsaXRfdmlvbGluKHRyaW09IEYsIGNvbG9yPSJ3aGl0ZSIsIHNjYWxlID0gImFyZWEiKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IERhdGFfc3VtbWFyeSxhZXMoeCA9IGdlbmUsIHk9IGV4cHIpLCBwY2g9MTksCiAgICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgwLjIpLHNpemU9IDEpICsgI+e7mOWItuWdh+WAvOS9jee9rgogIGdlb21fZXJyb3JiYXIoZGF0YSA9IERhdGFfc3VtbWFyeSwgYWVzKHltaW4gPSBleHByLWNpLCB5bWF4PSBleHByK2NpKSwgCiAgICAgICAgICAgICAgICB3aWR0aD0gMC4wNSwgCiAgICAgICAgICAgICAgICBwb3NpdGlvbj0gcG9zaXRpb25fZG9kZ2UoMC4yKSwgI+ivr+W3rue6v+S9jee9ru+8jOWSjOWdh+WAvOS9jee9ruebuOWMuemFjQogICAgICAgICAgICAgICAgY29sb3I9ImJsYWNrIiwKICAgICAgICAgICAgICAgIGFscGhhID0gMC43LAogICAgICAgICAgICAgICAgc2l6ZT0gMC41KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2IxZDZmYiIsICIjZmQ5OTk5IikpKyAKICBsYWJzKHk9KCJMb2cyIGV4cHJlc3Npb24iKSx4PU5VTEwsdGl0bGUgPSAiU3BsaXQgdmlvbGluIikgKyAKICB0aGVtZV9jbGFzc2ljKCkrIG15dGhlbWUgKyBzdGF0X2NvbXBhcmVfbWVhbnMoYWVzKGdyb3VwID0gc2FtcGxlKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5mb3JtYXQiLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC55ID0gbWF4KG1lcmdlX2V4cHIkZXhwciksCiAgICAgICAgICAgICAgICAgICAgICBoaWRlLm5zID0gRikKZ2dvYmoKZ2dzYXZlKCIyX3N1cGRzMHRvZHMxLnN2ZyIsIGRldmljZSA9IHN2ZywgcGxvdCA9IGdnb2JqLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEwKQpgYGAKCgoKYGBge3J9Cm15dGhlbWUgPC0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsY29sb3I9ImJsYWNrIixoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLGNvbG9yID0iYmxhY2siKSwgCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPSAxMixjb2xvciA9ICJibGFjayIpLAogICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxICksCiAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQ9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0gMTIpLAogICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGU9IGVsZW1lbnRfdGV4dChzaXplPSAxMikpIAoKIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvNDU2MTQ1NDcKR2VvbVNwbGl0VmlvbGluIDwtIGdncHJvdG8oIkdlb21TcGxpdFZpb2xpbiIsIEdlb21WaW9saW4sIGRyYXdfZ3JvdXAgPSBmdW5jdGlvbihzZWxmLCBkYXRhLCAuLi4sIGRyYXdfcXVhbnRpbGVzID0gTlVMTCl7CiAgZGF0YSA8LSB0cmFuc2Zvcm0oZGF0YSwgeG1pbnYgPSB4IC0gdmlvbGlud2lkdGggKiAoeCAtIHhtaW4pLCB4bWF4diA9IHggKyB2aW9saW53aWR0aCAqICh4bWF4IC0geCkpCiAgZ3JwIDwtIGRhdGFbMSwnZ3JvdXAnXQogIG5ld2RhdGEgPC0gcGx5cjo6YXJyYW5nZSh0cmFuc2Zvcm0oZGF0YSwgeCA9IGlmKGdycCUlMj09MSkgeG1pbnYgZWxzZSB4bWF4diksIGlmKGdycCUlMj09MSkgeSBlbHNlIC15KQogIG5ld2RhdGEgPC0gcmJpbmQobmV3ZGF0YVsxLCBdLCBuZXdkYXRhLCBuZXdkYXRhW25yb3cobmV3ZGF0YSksIF0sIG5ld2RhdGFbMSwgXSkKICBuZXdkYXRhW2MoMSxucm93KG5ld2RhdGEpLTEsbnJvdyhuZXdkYXRhKSksICd4J10gPC0gcm91bmQobmV3ZGF0YVsxLCAneCddKSAKICBpZiAobGVuZ3RoKGRyYXdfcXVhbnRpbGVzKSA+IDAgJiAhc2NhbGVzOjp6ZXJvX3JhbmdlKHJhbmdlKGRhdGEkeSkpKSB7CiAgICBzdG9waWZub3QoYWxsKGRyYXdfcXVhbnRpbGVzID49IDApLCBhbGwoZHJhd19xdWFudGlsZXMgPD0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxKSkKICAgIHF1YW50aWxlcyA8LSBnZ3Bsb3QyOjo6Y3JlYXRlX3F1YW50aWxlX3NlZ21lbnRfZnJhbWUoZGF0YSwgZHJhd19xdWFudGlsZXMpCiAgICBhZXN0aGV0aWNzIDwtIGRhdGFbcmVwKDEsIG5yb3cocXVhbnRpbGVzKSksIHNldGRpZmYobmFtZXMoZGF0YSksIGMoIngiLCAieSIpKSwgZHJvcCA9IEZBTFNFXQogICAgYWVzdGhldGljcyRhbHBoYSA8LSByZXAoMSwgbnJvdyhxdWFudGlsZXMpKQogICAgYm90aCA8LSBjYmluZChxdWFudGlsZXMsIGFlc3RoZXRpY3MpCiAgICBxdWFudGlsZV9ncm9iIDwtIEdlb21QYXRoJGRyYXdfcGFuZWwoYm90aCwgLi4uKQogICAgZ2dwbG90Mjo6OmdnbmFtZSgiZ2VvbV9zcGxpdF92aW9saW4iLCBncmlkOjpncm9iVHJlZShHZW9tUG9seWdvbiRkcmF3X3BhbmVsKG5ld2RhdGEsIC4uLiksIHF1YW50aWxlX2dyb2IpKQogIH0KICBlbHNlIHsKICAgIGdncGxvdDI6OjpnZ25hbWUoImdlb21fc3BsaXRfdmlvbGluIiwgR2VvbVBvbHlnb24kZHJhd19wYW5lbChuZXdkYXRhLCAuLi4pKQogIH0KfSkKCmdlb21fc3BsaXRfdmlvbGluIDwtIGZ1bmN0aW9uIChtYXBwaW5nID0gTlVMTCwgZGF0YSA9IE5VTEwsIHN0YXQgPSAieWRlbnNpdHkiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIsIC4uLiwgZHJhd19xdWFudGlsZXMgPSBOVUxMLCB0cmltID0gVFJVRSwgc2NhbGUgPSAiYXJlYSIsIG5hLnJtID0gRkFMU0UsIHNob3cubGVnZW5kID0gTkEsIGluaGVyaXQuYWVzID0gVFJVRSkgewogIGxheWVyKGRhdGEgPSBkYXRhLCBtYXBwaW5nID0gbWFwcGluZywgc3RhdCA9IHN0YXQsIGdlb20gPSBHZW9tU3BsaXRWaW9saW4sIHBvc2l0aW9uID0gcG9zaXRpb24sIHNob3cubGVnZW5kID0gc2hvdy5sZWdlbmQsIGluaGVyaXQuYWVzID0gaW5oZXJpdC5hZXMsIHBhcmFtcyA9IGxpc3QodHJpbSA9IHRyaW0sIHNjYWxlID0gc2NhbGUsIGRyYXdfcXVhbnRpbGVzID0gZHJhd19xdWFudGlsZXMsIG5hLnJtID0gbmEucm0sIC4uLikpCn0KYGBgCgoKCiMjIHNjYXR0ZXIg5q+U6L6DIGZpZy4zIERDTiDlkowgTFVNIOWcqCBGYk0g5LitIHN1cCB2cyB1bnN1cAojIyMgZHMyIC0+IGRzMApgYGB7cn0KYnN0X21vZGVsIDwtIHJlYWRSRFMoImRzMl9tb2RlbC5yZHMiKQpkczJfZGF0YSA8LSBnZXRfZGF0YV90YWJsZShkczIsIGhpZ2h2YXIgPSBGLCB0eXBlID0gImRhdGEiKQpJZGVudHMoZHMyKSA8LSBkczIkc2V1cmF0X2NsdXN0ZXJzCklkZW50cyhkczApIDwtIGRzMCRzZXVyYXRfY2x1c3RlcnMKdGVtcCA8LSBnZXRfZGF0YV90YWJsZShkczAsIGhpZ2h2YXIgPSBGLCB0eXBlID0gImRhdGEiKQpkczBfZGF0YSA8LSBtYXRyaXgoZGF0YT0wLCBucm93ID0gbGVuZ3RoKHJvd25hbWVzKGRzMl9kYXRhKSksIG5jb2wgPSBsZW5ndGgoY29sbmFtZXModGVtcCkpLCAKICAgICAgICAgICAgICAgICAgIGJ5cm93ID0gRkFMU0UsIGRpbW5hbWVzID0gbGlzdChyb3duYW1lcyhkczJfZGF0YSksY29sbmFtZXModGVtcCkpKQpmb3IoaSBpbiBpbnRlcnNlY3Qocm93bmFtZXMoZHMyX2RhdGEpLCByb3duYW1lcyh0ZW1wKSkpewogIGRzMF9kYXRhW2ksXSA8LSB0ZW1wW2ksXQp9CnJtKHRlbXApCmRzMF9sYWJlbCA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihJZGVudHMoZHMwKSkpCmNvbG5hbWVzKGRzMF9kYXRhKSA8LSBOVUxMCmRzMF90ZXN0X2RhdGEgPC0gbGlzdChkYXRhID0gdChhcyhkczBfZGF0YSwiZGdDTWF0cml4IikpLCBsYWJlbCA9IGRzMF9sYWJlbCkKZHMwX3Rlc3QgPC0geGdiLkRNYXRyaXgoZGF0YSA9IGRzMF90ZXN0X2RhdGEkZGF0YSxsYWJlbCA9IGRzMF90ZXN0X2RhdGEkbGFiZWwpCgoj6aKE5rWL57uT5p6cCnByZWRpY3RfZHMwX3Rlc3QgPC0gcHJlZGljdChic3RfbW9kZWwsIG5ld2RhdGEgPSBkczBfdGVzdCkKcHJlZGljdF9wcm9wX2RzMCA8LSBtYXRyaXgoZGF0YT1wcmVkaWN0X2RzMF90ZXN0LCBucm93ID0gbGVuZ3RoKGxldmVscyhJZGVudHMoZHMyKSkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IG5jb2woZHMwKSwgYnlyb3cgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChsZXZlbHMoSWRlbnRzKGRzMikpLGNvbG5hbWVzKGRzMCkpKQoKIyMg5b6X5Yiw5YiG576k57uT5p6cCmRzMF9yZXMgPC0gYXBwbHkocHJlZGljdF9wcm9wX2RzMCwyLGZ1bmMscm93bmFtZXMocHJlZGljdF9wcm9wX2RzMCkpCklkZW50cyhkczApIDwtIGZhY3RvcihkczBfcmVzLGxldmVscyA9IGMoMDo0KSkKdW1hcHBsb3QoZHMwKQpkczAkc3VwY2x1c3RlcmluZyA8LSBJZGVudHMoZHMwKSAj5L+d5a2Y55uR552j6IGa57G757uT5p6cCmBgYAoKYGBge3J9CklkZW50cyhkczApIDwtIGRzMCRzdXBjbHVzdGVyaW5nCnN1cF9kczBGQk0gPC0gc3Vic2V0KGRzMCwgaWRlbnQgPSAiMSIpCklkZW50cyhkczApIDwtIGRzMCRDbGFzc2lmaWNhdGlvbjEKdW5zdXBfZHMwRkJNIDwtIHN1YnNldChkczAsIGlkZW50ID0gIkZpYnJvbXlvY3l0ZSIpCnJlZl91bnN1cF9kczJGQk0gPC0gc3Vic2V0KGRzMiwgaWRlbnQgPSAiMSIpCgpkYXRhMSA8LSBGZXRjaERhdGEob2JqZWN0ID0gc3VwX2RzMEZCTSwgdmFycyA9IGMoIkxVTSIsICJBQ1RBMiIsIkJHTiIsIlRBR0xOIikpCnJvd25hbWVzKGRhdGExKSA8LSAgTlVMTApkYXRhMSRncm91cCA8LSAic3VwIgoKZGF0YTIgPC0gRmV0Y2hEYXRhKG9iamVjdCA9IHVuc3VwX2RzMEZCTSwgdmFycyA9IGMoIkxVTSIsICJBQ1RBMiIsIkJHTiIsIlRBR0xOIikpCnJvd25hbWVzKGRhdGEyKSA8LSAgTlVMTApkYXRhMiRncm91cCA8LSAidW5zdXAiCgpkYXRhMyA8LSBGZXRjaERhdGEob2JqZWN0ID0gcmVmX3Vuc3VwX2RzMkZCTSwgdmFycyA9IGMoIkxVTSIsICJBQ1RBMiIsIkJHTiIsIlRBR0xOIikpCnJvd25hbWVzKGRhdGEzKSA8LSAgTlVMTApkYXRhMyRncm91cCA8LSAicmVmIgoKZGF0YSA8LSByYmluZChkYXRhMSxkYXRhMixkYXRhMykKCmdncGxvdChkYXRhLCBhZXMoeD1MVU0sIHk9QkdOLCBjb2xvciA9IGdyb3VwLCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsYWxwaGEgPSAwLjEpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtICwgc2U9VFJVRSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCxjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpCgpnZ3Bsb3QoZGF0YSwgYWVzKHg9TFVNLCB5PUFDVEEyLCBjb2xvciA9IGdyb3VwLCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsYWxwaGEgPSAwLjEpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtICwgc2U9VFJVRSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCxjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpCgpnZ3Bsb3QoZGF0YSwgYWVzKHg9VEFHTE4sIHk9QUNUQTIsIGNvbG9yID0gZ3JvdXAsIGdyb3VwID0gZ3JvdXApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMyxhbHBoYSA9IDAuMSkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9bG0gLCBzZT1UUlVFKSArCiAgdGhlbWVfY2xhc3NpYygpICsgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCxjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMSksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShzaXplID0gMSksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSkKCmBgYAojIyBzY2F0dGVyIOavlOi+gyBmaWcuMyBEQ04g5ZKMIExVTSDlnKggRmJNIOS4rSBzdXAgdnMgdW5zdXAKIyMjIGRzMiAtPiBkczEKYGBge3J9CmJzdF9tb2RlbCA8LSByZWFkUkRTKCJkczJfbW9kZWwucmRzIikKZHMyX2RhdGEgPC0gZ2V0X2RhdGFfdGFibGUoZHMyLCBoaWdodmFyID0gRiwgdHlwZSA9ICJkYXRhIikKSWRlbnRzKGRzMikgPC0gZHMyJHNldXJhdF9jbHVzdGVycwpJZGVudHMoZHMxKSA8LSBkczEkc2V1cmF0X2NsdXN0ZXJzCnRlbXAgPC0gZ2V0X2RhdGFfdGFibGUoZHMxLCBoaWdodmFyID0gRiwgdHlwZSA9ICJkYXRhIikKZHMxX2RhdGEgPC0gbWF0cml4KGRhdGE9MCwgbnJvdyA9IGxlbmd0aChyb3duYW1lcyhkczJfZGF0YSkpLCBuY29sID0gbGVuZ3RoKGNvbG5hbWVzKHRlbXApKSwgCiAgICAgICAgICAgICAgICAgICBieXJvdyA9IEZBTFNFLCBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoZHMyX2RhdGEpLGNvbG5hbWVzKHRlbXApKSkKZm9yKGkgaW4gaW50ZXJzZWN0KHJvd25hbWVzKGRzMl9kYXRhKSwgcm93bmFtZXModGVtcCkpKXsKICBkczFfZGF0YVtpLF0gPC0gdGVtcFtpLF0KfQpybSh0ZW1wKQpkczFfbGFiZWwgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoSWRlbnRzKGRzMSkpKQpjb2xuYW1lcyhkczFfZGF0YSkgPC0gTlVMTApkczFfdGVzdF9kYXRhIDwtIGxpc3QoZGF0YSA9IHQoYXMoZHMxX2RhdGEsImRnQ01hdHJpeCIpKSwgbGFiZWwgPSBkczFfbGFiZWwpCmRzMV90ZXN0IDwtIHhnYi5ETWF0cml4KGRhdGEgPSBkczFfdGVzdF9kYXRhJGRhdGEsbGFiZWwgPSBkczFfdGVzdF9kYXRhJGxhYmVsKQoKI+mihOa1i+e7k+aenApwcmVkaWN0X2RzMV90ZXN0IDwtIHByZWRpY3QoYnN0X21vZGVsLCBuZXdkYXRhID0gZHMxX3Rlc3QpCnByZWRpY3RfcHJvcF9kczEgPC0gbWF0cml4KGRhdGE9cHJlZGljdF9kczFfdGVzdCwgbnJvdyA9IGxlbmd0aChsZXZlbHMoSWRlbnRzKGRzMikpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSBuY29sKGRzMSksIGJ5cm93ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QobGV2ZWxzKElkZW50cyhkczIpKSxjb2xuYW1lcyhkczEpKSkKCiMjIOW+l+WIsOWIhue+pOe7k+aenApkczFfcmVzIDwtIGFwcGx5KHByZWRpY3RfcHJvcF9kczEsMixmdW5jLHJvd25hbWVzKHByZWRpY3RfcHJvcF9kczEpKQpJZGVudHMoZHMxKSA8LSBmYWN0b3IoZHMxX3JlcyxsZXZlbHMgPSBjKDA6NCkpCnVtYXBwbG90KGRzMSkKZHMxJHN1cGNsdXN0ZXJpbmcgPC0gSWRlbnRzKGRzMSkgI+S/neWtmOebkeedo+iBmuexu+e7k+aenApgYGAKCmBgYHtyfQpJZGVudHMoZHMxKSA8LSBkczEkc3VwY2x1c3RlcmluZwpzdXBfZHMxRkJNIDwtIHN1YnNldChkczEsIGlkZW50ID0gIjEiKQpJZGVudHMoZHMxKSA8LSBkczEkQ2xhc3NpZmljYXRpb24xCnVuc3VwX2RzMUZCTSA8LSBzdWJzZXQoZHMxLCBpZGVudCA9ICJGaWJyb215b2N5dGUiKQpyZWZfdW5zdXBfZHMyRkJNIDwtIHN1YnNldChkczIsIGlkZW50ID0gIjEiKQoKZGF0YTEgPC0gRmV0Y2hEYXRhKG9iamVjdCA9IHN1cF9kczFGQk0sIHZhcnMgPSBjKCJMVU0iLCAiQUNUQTIiLCJCR04iLCJUQUdMTiIpKQpyb3duYW1lcyhkYXRhMSkgPC0gIE5VTEwKZGF0YTEkZ3JvdXAgPC0gInN1cCIKCmRhdGEyIDwtIEZldGNoRGF0YShvYmplY3QgPSB1bnN1cF9kczFGQk0sIHZhcnMgPSBjKCJMVU0iLCAiQUNUQTIiLCJCR04iLCJUQUdMTiIpKQpyb3duYW1lcyhkYXRhMikgPC0gIE5VTEwKZGF0YTIkZ3JvdXAgPC0gInVuc3VwIgoKZGF0YTMgPC0gRmV0Y2hEYXRhKG9iamVjdCA9IHJlZl91bnN1cF9kczJGQk0sIHZhcnMgPSBjKCJMVU0iLCAiQUNUQTIiLCJCR04iLCJUQUdMTiIpKQpyb3duYW1lcyhkYXRhMykgPC0gIE5VTEwKZGF0YTMkZ3JvdXAgPC0gInJlZiIKCmRhdGEgPC0gcmJpbmQoZGF0YTEsZGF0YTIsZGF0YTMpCgpnZ3Bsb3QoZGF0YSwgYWVzKHg9TFVNLCB5PUJHTiwgY29sb3IgPSBncm91cCwgZ3JvdXAgPSBncm91cCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLGFscGhhID0gMC4xKSArIAogIGdlb21fc21vb3RoKG1ldGhvZD1sbSAsIHNlPVRSVUUpICsKICB0aGVtZV9jbGFzc2ljKCkgKyAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAxKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKHNpemUgPSAxKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQoKZ2dwbG90KGRhdGEsIGFlcyh4PUxVTSwgeT1BQ1RBMiwgY29sb3IgPSBncm91cCwgZ3JvdXAgPSBncm91cCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLGFscGhhID0gMC4xKSArIAogIGdlb21fc21vb3RoKG1ldGhvZD1sbSAsIHNlPVRSVUUpICsKICB0aGVtZV9jbGFzc2ljKCkgKyAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAxKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKHNpemUgPSAxKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQoKZ2dwbG90KGRhdGEsIGFlcyh4PVRBR0xOLCB5PUFDVEEyLCBjb2xvciA9IGdyb3VwLCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsYWxwaGEgPSAwLjEpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtICwgc2U9VFJVRSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCxjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpCgpgYGAKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDdHJsK0FsdCtJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ3RybCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLgoKVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLgo=